package feed

import (
	"gitee.com/mootok/mootok/src/models"
	"gitee.com/mootok/mootok/src/storage/database"
	"gitee.com/mootok/mootok/src/storage/redis"
	"github.com/gin-gonic/gin"
	redis3 "github.com/redis/go-redis/v9"
	"github.com/sirupsen/logrus"
)

// FollowFeedOperation adds user's video to another user's feed list
func FollowFeedOperation(c *gin.Context, followRelation models.FollowRelation, logger *logrus.Entry) (err error) {
	followId := followRelation.FollowId
	fansId := followRelation.FansId
	var videoList []models.Video

	if err := database.Client.Where("user_id = ?", followId).Find(&videoList).Error; err != nil {
		logger.Errorf("follow_id  select from db faile %v", err)
		return err
	}

	redisKey := genFollowVideoFeedListKey(fansId)
	//异步写回或者删除

	feedRelationList := make([]models.UserVideoFeedRelation, len(videoList))
	//写入到redis中
	for i := 0; i < len(feedRelationList); i++ {
		score := float64(videoList[i].CreatedAt.Unix())
		if err := redis.Client.ZAdd(c, redisKey, redis3.Z{
			Score:  score,
			Member: videoList[i].ID}).Err(); err != nil {
			logger.Errorf("add user_video_feed to redis faile %v", err)
			return err
		}
		feedRelationList[i].UserId = fansId
		feedRelationList[i].VideoId = videoList[i].ID
		feedRelationList[i].Score = score
	}
	go asyncStoreAfterFollow(c, feedRelationList, logger)

	return err
}

// UnFollowFeedOperation removes user's video to another user's feed list
func UnFollowFeedOperation(c *gin.Context, followRelation models.FollowRelation, logger *logrus.Entry) (err error) {
	followId := followRelation.FollowId
	fansId := followRelation.FansId
	var videoList []models.Video

	if err = database.Client.Where("user_id = ?", followId).Find(&videoList).Error; err != nil {
		logger.Errorf("follow_id select  from db faile %v", err)
		return err
	}
	redisKey := genFollowVideoFeedListKey(fansId)

	videoIdList := make([]int, len(videoList))

	for i := 0; i < len(videoIdList); i++ {
		if err := redis.Client.ZRem(c, redisKey, videoList[i].ID).Err(); err != nil {
			logger.Errorf("remove user_video_feed from redis faile %v", err)
			continue
		}
		videoIdList[i] = videoList[i].ID
	}
	go asyncRemoveAfterUnFollow(c, videoIdList, fansId, logger)
	return err
}

func asyncStoreAfterFollow(c *gin.Context, feedRelationList []models.UserVideoFeedRelation, logger *logrus.Entry) {
	//开启事务
	var err error
	tx := database.Client.WithContext(c).Begin()
	defer func() {
		if err != nil {
			logger.Errorf("rollback %v", err)
			tx.Rollback()
			return
		}
		tx.Commit()
	}()
	err = tx.Create(&feedRelationList).Error
	if err != nil {
		logger.Errorf("create user_video_feed to db faile %v", err)
		return
	}
}

func asyncRemoveAfterUnFollow(c *gin.Context, videoIdList []int, fansId int, logger *logrus.Entry) {
	//开启事务
	var err error
	tx := database.Client.WithContext(c).Begin()
	defer func() {
		if err != nil {
			logger.Errorf("rollback %v", err)
			tx.Rollback()
			return
		}
		tx.Commit()
	}()

	err = tx.Where("video_id in (?)", videoIdList).Where("user_id = ?", fansId).
		Delete(&models.UserVideoFeedRelation{}).Error
	if err != nil {
		logger.Errorf("remove user_video_feed from db faile %v", err)
		return
	}
}
